<template>
	<view class="warp" :id="id">
		<scroll-view scroll-x :scroll-left="scrollLeft" class="scroll" scroll-with-animation>
			<view class="tab-item-box">
				<view class="tab-item"  v-for="(item,index) in list" :key="index"  
				@tap="clickTab(index)"
				:id="'tab-item-' + index"
				:style="[tabItemStyle(index,item[name] || item['name'])]"
				>{{ item[name] || item['name'] }}
				</view>
			</view>
			
		</scroll-view>
		
	</view>
</template>

<script>
	export default{
		props:{
			list:{
				type:Array,
				default(){
					return [
						
					]
				}
			},
			// 单个tab的左右内边距
			gutter: {
			  type: Number,
			  default: 30
			},
			//激活时背景颜色
			activeBgColor:{
				type:String,
				default:'#01BEFF'
			},
			//未激活时背景颜色
			inactiveBgColor:{
				type:String,
				default:'transparent'
			},
			// 选中时的颜色
		    activeColor: {
			  type: String,
			  default: "white"
		    },
		    // 列表数据tab名称的属性
		    name: {
			  type: String,
			  default: 'name'
		    },
		    // 未被选中时的颜色
		    inactiveColor: {
			  type: String,
			  default: '#080808'
		    },
			//当前选中索引
			current:{
				type:Number,
				default:0
			},
			// 过渡动画时长(s)
		    duration: {
				type: Number,
				default: 0.3
		    },
		},
		computed:{
		  // tabItem样式
		  tabItemStyle(index) {
			return index => {
			  let style = {
				fontSize: this.fontSizeStyle || '28rpx',
				marginLeft:this.gutter+'rpx',
			  }
			  if (index === this.currentIndex) {
				style.backgroundColor = this.activeBgColor
				style.color = this.activeColor
				Object.assign(style, this.activeItemStyle)
			  } else {
				style.backgroundColor = this.inactiveBgColor;
				style.color = this.inactiveColor
				Object.assign(style, this.inactiveItemStyle)
			  }
			  if(index == 0){
				  style.marginLeft = '0rpx';
			  }
			  return style
			}
		  }			
		},
		watch: {
		  // 监听tab的变化，重新计算tab菜单信息
		  list(newValue, oldValue) {
			// list变化时，重置内部索引，防止出现超过数据边界的问题
			if (newValue.length !== oldValue.length) this.currentIndex = 0
			this.$nextTick(() => {
			  this.init()
			})
		  },
		  current: {
			handler(val) {
			  this.$nextTick(() => {
				this.currentIndex = val
				this.scrollByIndex()
			  })
			},
			immediate: true
		  }
		},
		data(){
			return {
				id: this.uuid(),
				scrollLeft:0,
				// 当前选中的itemIndex
				currentIndex: this.current,
				// 存放查询后tab菜单的节点信息
				tabQueryInfo: [],
				// 组件宽度
				componentWidth: 0,
				// 底部滑块的移动距离
				scrollBarLeft: 0,
				// 组件到屏幕左边的巨鹿
				componentLeft: 0,
				// 标记底部滑块是否第一次移动，第一次移动的时候不触发动画
				barMoveFirst: true,
				
			}
		},
		mounted() {
		  this.init()
		},
		methods:{
			  // 初始化变量
			  async init() {
				// 获取tabs组件的信息
				let tabRect = await this._tGetRect('#' + this.id)
				// 计算组件的宽度
				this.componentLeft = tabRect.left
				this.componentWidth = tabRect.width
				this.getTabRect()
			  },
			  // 查询tab的布局信息
			  getTabRect() {
				let query = uni.createSelectorQuery().in(this)
				  // 遍历所有的tab
				  for (let i = 0; i < this.list.length; i++) {
					query.select(`#tab-item-${i}`).fields({
					  size: true,
					  rect: true
					})
				  }
				  query.exec((res) => {
					this.tabQueryInfo = res
					// 初始滚动条和底部滑块的位置
					this.scrollByIndex()
				  })
			   },
			  scrollByIndex() {
				// 当前获取tab的布局信息
				let tabInfo = this.tabQueryInfo[this.currentIndex]
				if (!tabInfo) return
				
				// 活动tab的宽度
				let tabWidth = tabInfo.width
				// 活动item的左边到组件左边的距离
				let offsetLeft = tabInfo.left - this.componentLeft
				// 计算scroll-view移动的距离
				let scrollLeft = offsetLeft - (this.componentWidth - tabWidth) / 2
				this.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft
				
				// 计算当前滑块需要移动的距离，当前活动item的中点到左边的距离减去滑块宽度的一半
				let left = tabInfo.left + tabInfo.width / 2 - this.componentLeft
				
				// 计算当前活跃item到组件左边的距离
				this.scrollBarLeft = left - uni.upx2px(this.barWidth) / 2
				
				// 防止在计算时出错，所以延迟执行标记不是第一次移动
				if (this.barMoveFirst) {
				  setTimeout(() => {
					this.barMoveFirst = false
				  }, 100)
				}
			  },				
			  //点击tab菜单
			  clickTab(index) {
				console.log("点击tab菜单")
				if (index === this.currentIndex) return
				this.$emit('change', index)
			  },
			  _tGetRect(selector, all) {
			    return new Promise((resolve) => {
			      uni.createSelectorQuery()
			        .in(this)[all ? 'selectAll' : 'select'](selector)
			        .boundingClientRect(rect => {
			          if (all && Array.isArray(rect) && rect.length) {
			            resolve(rect)
			          }
			          if (!all && rect) {
			            resolve(rect)
			          }
			        })
			        .exec()
			    })
			  },
			  uuid(len = 32, firstT = true, radix = null) {
			  	let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
			  	let uuid = []
			  	radix = radix || chars.length
			  
			  	if (len) {
			  		// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
			  		for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
			  	} else {
			  		let r;
			  		// rfc4122标准要求返回的uuid中,某些位为固定的字符
			  		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
			  		uuid[14] = '4'
			  
			  		for (let i = 0; i < 36; i++) {
			  			if (!uuid[i]) {
			  				r = 0 | Math.random() * 16
			  				uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
			  			}
			  		}
			  	}
			  	// 移除第一个字符,并用t替代,因为第一个字符为数值时,该uuid不能用作id或者class
			  	if (firstT) {
			  		uuid.shift()
			  		return 't' + uuid.join('')
			  	} else {
			  		return uuid.join('')
			  	}
			  }
			  
		}
	}
	
</script>

<style lang="scss" scoped>
	.warp{
		width: 100%;
		margin: 30rpx 0rpx;
		box-sizing: border-box;
		
		.scroll{
			width: 100%;
			position: relative;
		    width: 100%;
		    white-space: nowrap;
			
			.tab-item-box{
				display: flex;
				justify-content: flex-start;
				position: relative;
				white-space: nowrap;
				
				.tab-item{
					// margin-left: 30rpx;
					color: white;
					padding: 6rpx 14rpx;
					border-radius: 1000rpx;
					text-align: center;
					backgroundColor:#F4F4F4;
				}
			}
			
		}
		
		
	}
</style>
